<?php

/**
function debug () {
	$args = func_get_args();
	if (! headers_sent()) header('Content-type: text/html; charset=utf-8');
	echo "<pre>\n";
	foreach ($args as $value) {
		if (is_null($value)) {
			echo '[is_null]';
		}
		elseif (is_bool($value) || empty($value)) {
			var_dump($value);
		}
		else {
			print_r($value);
		}
		echo "\n";
	}
	$trace = debug_backtrace ();
	$next = array_merge ( array ('line' => '?', 'file' => '[internal]'), $trace [0] );
	unset($trace);
	echo '位置:',$next ['file'] . "\t第" . $next ['line'] . "行.\n";
	exit();
}
 */

function debug ()
{

	//if (! class_exists('Debug', FALSE))include CORE_PATH . 'debug.php';
	$args = func_get_args();
	call_user_func_array(array(
		'Debug', 
		'thin'
	), $args);
}

function trace_debug ()
{

	//if (! class_exists('Debug', FALSE))include CORE_PATH . 'debug.php';
	$args = func_get_args();
	call_user_func_array(array(
		'Debug', 
		'rich'
	), $args);
}

class Debug
{

	/**
	 * thin
	 * 调试参数中的变量并中断程序的执行，参数可以为任意多个,类型任意。
	 * 用于类库加载不完善时，简单显示调试信息
	 *
	 * <code>
	 * debug($var1,$obj1,$array1[,]................);
	 * debug($var1,'debug');
	 * </code>
	 */
	public static function thin ()
	{

		$args = func_get_args();
		if (! headers_sent())
			header('Content-type: text/html; charset=utf-8');
		echo "<pre>\n----------------------------调试信息.---------------------------\n";
		foreach ($args as $value)
		{
			if (is_null($value))
			{
				echo '[is_null]';
			}
			elseif (is_bool($value) || empty($value))
			{
				var_dump($value);
			}
			else
			{
				print_r($value);
			}
			echo "\n";
		}
		$trace = debug_backtrace();
		array_splice($trace, 0, 2);
		$next = array_merge(array(
			
			'line' => '??', 
			'file' => '[internal]', 
			'class' => null, 
			'function' => '[main]'
		), $trace[0]);
		
		if (strpos($next['file'], ROOT_PATH) !== false)
		{
			$next['file'] = str_replace(ROOT_PATH, '>ROOT_PATH' . DS, $next['file']);
		}
		echo "\n-----------------------------调试结束---------------------------\n文件位置:";
		echo $next['file'] . "\t第" . $next['line'] . "行.\n";
		if (defined('EXEC_START_TIME'))
			register_shutdown_function(array(
				
				'Debug', 
				'timer'
			), 6, true);
		die();
	}

	/**
	 * 计时器
	 *
	 * @param integer $decimals 显示精度
	 * @param boolean $echo		是否直接显示,为false则返回
	 * @return string
	 */
	public static function timer ($decimals = 6 ,$print = false)
	{

		$exec_time = number_format(microtime(TRUE) - EXEC_START_TIME, $decimals);
		if (! $print)
		{
			return $exec_time;
		}
		else
		{
			$memory = self::memory_usage($decimals, 'M');
			$str = '<p align="center" style="color:#999;font-size:9px;" class="kp-meta">
			Powered by Emvc! Parse Time:' . $exec_time . 's, using ' . $memory . 'MB of memory!</p>';
			echo $str;
			return;
		}
	}

	/**
	 * Quick debugging of any variable. Any number of parameters can be set.
	 *
	 * @return  string
	 */
	public static function dump ()
	{

		if (func_num_args() === 0)
			return;
		$params = func_get_args(); // Get params
		$output = array();
		foreach ($params as $var)
			$output[] = '<pre>(' . gettype($var) . ') ' . htmlspecialchars(print_r($var, TRUE)) . '</pre>';
		return implode("\n", $output);
	}

	public static function rich ()
	{

		$args = func_get_args();
		if ($args)
			$args = call_user_func_array(array(
				
				__CLASS__, 
				'dump'
			), $args);
		$trace = debug_backtrace();
		array_splice($trace, 0, 2);
		$location = array_merge(array(
			
			'line' => '?', 
			'file' => '[internal]'
		), array_shift($trace));
		$location['file'] = path::render($location['file']);
		$location = '<div><pre>调试位置:' . $location['file'] . '[' . $location['line'] . ']</pre></div>';
		$trace = self::backtrace($trace);
		$execution_time = self::timer();
		$memory = self::memory_usage(6, 'M') . 'MB';
		if (! headers_sent())
			header('Content-type: text/html; charset=utf-8');
		if (class_exists('Path'))
		{
			$file = Loader::find('views.debuger');
			if ($file)
			{
				include $file;
			}
		}
		else
		{
			echo <<<HDOC
<style type="text/css">
h3 { color:#fff; font-size:16px; padding:8px 6px; margin:0 0 8px; background:#690; text-align:center;}
tt,pre{ font-family:monospace; padding:2px 4px; font-size:12px; color:#333;white-space:pre-wrap;white-space:-moz-pre-wrap;word-wrap:break-word;}
pre{background:#eaeee5;border:solid 0 #D6D8D1; border-width:0 1px 1px 0;}
</style>
<div style="margin:0 auto;width:90%;">
	<h3>调试信息</h3>
	$args $location
	<h3>Trace信息</h3>
	$trace
</div>
HDOC;
		}
		die();
	}

	public static function memory_usage ($decimals = 4 ,$unit = 'M')
	{

		static $func;
		if ($func === NULL)
			$func = function_exists('memory_get_usage');
		if (! $func)
			return 0;
		$memory = memory_get_usage();
		switch ($unit)
		{
			case 'M':
				$memory = $memory / 1024 / 1024;
				break;
			case 'K':
				$memory = $memory / 1024;
				break;
			case 'G':
				$memory = $memory / 1024 / 1024 / 1024;
			default:
		
		}
		return number_format($memory, $decimals);
	}

	/**
	 * Displays nice backtrace information.
	 * @see http://php.net/debug_backtrace
	 *
	 * @param   array   backtrace generated by an exception or debug_backtrace
	 * @return  string
	 */
	public static function backtrace ($trace)
	{

		if (! is_array($trace))
			return;
		$output = array();
		foreach ($trace as $entry)
		{
			$temp = '<li>';
			if (isset($entry['file']))
				$temp .= I18n::__('core.error_file_line', path::render($entry['file']), $entry['line']);
			$temp .= '<pre>';
			if (isset($entry['class']))
				$temp .= $entry['class'] . $entry['type'];
			$temp .= $entry['function'] . '( ';
			if (isset($entry['args']) and is_array($entry['args']))
			{
				$sep = '';
				while ($arg = array_shift($entry['args']))
				{
					if (is_string($arg) and is_file($arg))
						$arg = path::render($arg);
					$temp .= $sep . html::specialchars(print_r($arg, TRUE));
					//$temp .= $sep .htmlspecialchars(print_r($arg, TRUE), ENT_QUOTES, 'UTF-8', FALSE);
					$sep = ', ';
				}
			}
			$temp .= ' )</pre></li>';
			$output[] = $temp;
		}
		return '<ul class="backtrace">' . implode("\n", $output) . '</ul>';
	}

	function verbose ()
	{

		$args = func_get_args();
		ob_start();
		print_r($args);
		$output = ob_get_clean();
		return $output;
	}
}
